package org.testis.gui.mvc.controller.dynamicmap;

import org.testis.gui.mvc.controller.*;
import org.testis.gui.mvc.controller.testdesign.OperationResultObject;
import org.testis.gui.mvc.utilities.Operation;
import org.testis.gui.mvc.utilities.OperationExecutor;
import org.testis.gui.mvc.view.testdesign.TreeViewPanel;
import org.testis.utils.StringVerification;
import org.testis.utils.Timer;
import org.testis.utils.tree.MyDefaultMutableTreeNode;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.apache.commons.collections.MultiHashMap;
import org.orm.PersistentException;
import org.orm.PersistentTransaction;
import org.testis.orm.classes.*;
import org.testis.orm.manager.TestisDbPersistentManager;
import org.testis.orm.refinedclasses.DynamicMapDesignTreeNode;
import org.testis.orm.refinedclasses.DynamicMapObject;
import org.testis.orm.refinedclasses.DynamicMapParameter;
import org.testis.utils.middleware.DynamicMap;
import org.testis.utils.middleware.NoSuchDeviceException;

/**
 *
 * @author Cahit Emir Erel
 */
public class DynamicMapTreeController extends AbstractController implements
        Draggable, OperationExecutor, Selectable {

    public static final String NODE_DELETE = "DynamicMapDelete";
    public static final String TREE_LOAD = "DynamicMapLoadTree";
    public static final String TREE_SAVE = "DynamicMapSaveTree";
    public static final String TREE_RELOAD = "DynamicMapReloadTree";
    public static final String TREE_REFRESH = "DynamicMapRefreshTree";
    public static final String SELECT_DESIGN_PART = "DynamicMapSelectedNode";
    public static final String SHOW_PROPERTIES = "DynamicMapProperties";
    public static final String DESTINATION = "DynamicMapDestination";
    public static final String SOURCE = "DynamicMapSource";
    public static final String COMPARE_MODE_ON = "DynamicMapCompareMode";
    public static final String CLEAR_SELECTION_PROPERTY = "DynamicMapClearSelection";
    private MyDefaultMutableTreeNode[] m_selected;
    private MyDefaultMutableTreeNode[] m_notSelected;
    private boolean m_sourceSelected;
    private MultiHashMap cloneIdsOfOriginals;
    private HashMap<Integer, Integer> newIdsOfOriginals;
    private String m_lastSearchValue;

    public DynamicMapTreeController() {
        super();
    }

    public void operationRefreshTree() {
        setModelProperty(TREE_REFRESH,
                true);
    }

    public synchronized void operationHandleClones(SaveAble controller,
            DynamicMapDesignTreeNode node,
            HashMap<String, Object> params) {

        Timer t = new Timer();
        t.reset();
        boolean result = true;
        if (!node.isClone() && node.isSafeToDelete()) {

            result = controller.operationSave(params,
                    node,
                    true);
        } // This node is an original with no clones
        else {
            result = showListOfClones(controller,
                    node,
                    params);
        } // This node is a clone or an original that has clones
        t.print(" operationHandleSaveClones  in ms:");
        if (result) {
            reloadAllTrees();
        } else {
            TestDesignControllerList.newInstance().getTreeController().
                    operationGenerateErrorMessage("Invalid save...",
                    "ERROR");
        }
    }

    public synchronized void operationHandleAdd(DynamicMapAddable controller,
            DynamicMapDesignTreeNode node,
            HashMap<String, Object> params) {
        Timer t = new Timer();
        t.reset();
        boolean result = false;
        if (node == null || (!node.isClone() && node.isSafeToDelete())) {
            DynamicMapDesignTreeNode adddedNode = controller.operationAddObject(params,
                    node, 0);
            if (adddedNode != null) {
                result = true;
            }
        } // This node is an original with no clones
        else {
            result = showListOfAdds(controller,
                    node,
                    params);
        } // This node is a clone or an original that has clones
        t.print(" operationHandleAdd  in ms:");
        if (result) {
            reloadAllTrees();
        } else {
            TestDesignControllerList.newInstance().getTreeController().
                    operationGenerateErrorMessage("Invalid Add...",
                    "ERROR");
        }
    }

    public void operationGenerateErrorMessage(String message,
            String title) {
        TreeViewPanel.showMessageDialog(message,
                title);
    }

    synchronized public boolean operationDeleteTreeNodeInternal(
            DynamicMapDesignTreeNode node,
            OperationResultObject result) {
        if (node == null) {
            result.setResult(false);
            return false;
        }
        T_dmap_designtree[] childNodes =node.getReference().t_dmap_designtree.toArray();
        int max = childNodes.length;
        validateIntegrity(node);

        for (int i = max - 1; i >= 0; i--) {
            operationDeleteTreeNodeInternal(DynamicMapDesignTreeNode.getNode(childNodes[i]),
                    result);
        }

        if (node.delete()) {
            result.setResult(true);
            node = null;
            return true;
        } else {
            result.setResult(false);
            System.out.println("FAILED to delete node with name:"+ node.getName());
            return false;
        }
    }

    public boolean safeDeleteWithTransaction(MyDefaultMutableTreeNode deleteNode, boolean startTransaction) {
        PersistentTransaction t = null;
        try {
            if (startTransaction) {
                t = TestisDbPersistentManager.instance().
                        getSession().beginTransaction();
            }
            try {
                OperationResultObject result = new OperationResultObject(
                        true);
                operationDeleteTreeNodeInternal((DynamicMapDesignTreeNode) deleteNode.getUserObject(),
                        result);
                if (result.isResult() && startTransaction) {
                    t.commit();
                    return true;
                } else if (startTransaction) {
                    try {
                        t.rollback();
                    } catch (PersistentException ex1) {
                        ex1.printStackTrace();
                    }
                    operationGenerateErrorMessage("Can not delete node with node data: "
                            + deleteNode.toString(),
                            "Error!");
                } else {
                    return true;
                }
            } catch (Exception ex) {
                try {
                    if (t != null) {
                        t.rollback();
                    }
                } catch (PersistentException ex1) {
                    ex1.printStackTrace();

                }
                ex.printStackTrace();
                operationGenerateErrorMessage("Can not delete node with node data: "
                        + deleteNode.toString(),
                        "Error!");
            }
        } catch (Exception ex) {

            operationGenerateErrorMessage("Can not start transaction "
                    + deleteNode.toString(),
                    "Error!");
            ex.printStackTrace();
        }
        return false;
    }

    public synchronized void operationHandleDelete(
            MyDefaultMutableTreeNode deleteNode) {

        Timer t = new Timer();
        t.reset();
        boolean result = false;
        DynamicMapDesignTreeNode node =
                (DynamicMapDesignTreeNode) deleteNode.getUserObject();
        if (node == null || (!node.isClone() && node.isSafeToDelete())) {
            result = safeDeleteWithTransaction(deleteNode, true);
        } // This node is an original with no clones
        else {
            result = showListOfDeletes(deleteNode);
        } // This node is a clone or an original that has clones
        t.print(" operationHandleDelete  in ms:");

        reloadAllTrees();
        if (!result) {
            TestDesignControllerList.newInstance().getTreeController().
                    operationGenerateErrorMessage("Invalid delete...",
                    "ERROR");
        }

    }

    public synchronized void operationHandlePasteClone(
            DynamicMapDesignTreeNode clone,
            MyDefaultMutableTreeNode targetNode) {

        Timer t = new Timer();
        t.reset();
        boolean result = false;
        DynamicMapDesignTreeNode node =
                (DynamicMapDesignTreeNode) targetNode.getUserObject();
        if (node == null || (!node.isClone() && node.isSafeToDelete())) {
            result = safeCloneWithTransaction(clone,
                    (DynamicMapDesignTreeNode) targetNode.getUserObject(),
                    targetNode.getChildCount(), true);
        } // This node is an original with no clones
        else {
            result = showListOfPasteClone(clone,
                    targetNode);
        } // This node is a clone or an original that has clones
        t.print(" operationHandlePasteClone  in ms:");
        if (result) {
            reloadAllTrees();
        } else {
            TestDesignControllerList.newInstance().getTreeController().
                    operationGenerateErrorMessage("Invalid paste clone...",
                    "ERROR");
        }
    }

    private boolean safeCopyWithTransaction(DynamicMapDesignTreeNode copy,
            DynamicMapDesignTreeNode targetNode, boolean oneToToneCopy,
            int childIndex, boolean startTransaction) {
        OperationResultObject result = new OperationResultObject(
                true);
        PersistentTransaction t = null;
        try {
            if (startTransaction) {
                t = TestisDbPersistentManager.instance().
                        getSession().beginTransaction();
            }
            operationPasteCopyInternal(copy,
                    targetNode,
                    oneToToneCopy,
                    result, childIndex);
            if (result.isResult() && startTransaction) {
                if (oneToToneCopy) {
                    Set keySet = newIdsOfOriginals.keySet();
                    Iterator<Integer> setIter = keySet.iterator();
                    while (setIter.hasNext()) {
                        Integer oldOriginalId = setIter.next();
                        Integer newOriginalId = newIdsOfOriginals.get(oldOriginalId);
                        DynamicMapDesignTreeNode originalNode = DynamicMapDesignTreeNode.getNodeById(newOriginalId);
                        List list = (List) cloneIdsOfOriginals.get(oldOriginalId);
                        if (list != null) {
                            for (int i = 0; i < list.size(); i++) {
                                Integer newCloneId = (Integer) list.get(i);
                                DynamicMapDesignTreeNode node = DynamicMapDesignTreeNode.getNodeById(newCloneId);
                                node.getReference().setClone(originalNode.getReference());
                                //refresh node
                                node = DynamicMapDesignTreeNode.getNodeById(newCloneId);
                                node.getReference().save();
                                originalNode.getReference().save();
                            }
                        }
                    }
                }
                t.commit();
            }
        } catch (Exception ex) {
            result.setResult(false);
            if (t != null) {
                try {
                    t.rollback();
                } catch (PersistentException ex1) {
                    ex1.printStackTrace();
                }
            }
            ex.printStackTrace();
        }
        return result.isResult();
    }

    public synchronized void operationHandlePasteCopy(
            DynamicMapDesignTreeNode copy,
            MyDefaultMutableTreeNode targetNode,
            boolean oneToToneCopy) {
        Timer t = new Timer();
        t.reset();
        boolean result = false;
        if (oneToToneCopy) {
            cloneIdsOfOriginals = new MultiHashMap();
            newIdsOfOriginals = new HashMap<Integer, Integer>();
        }
        DynamicMapDesignTreeNode node =
                (DynamicMapDesignTreeNode) targetNode.getUserObject();
        if (node == null || (!node.isClone() && node.isSafeToDelete())) {
            result = safeCopyWithTransaction(copy,
                    (DynamicMapDesignTreeNode) targetNode.getUserObject(),
                    oneToToneCopy, targetNode.getChildCount(), true);
        } // This node is an original with no clones
        else {
            result = showListOfPasteCopy(copy,
                    targetNode,
                    oneToToneCopy);
        } // This node is a clone or an original that has clones
        t.print(" operationHandlePasteCopy  in ms:");
        if (result) {
            reloadAllTrees();
        } else {
            TestDesignControllerList.newInstance().getTreeController().
                    operationGenerateErrorMessage("Invalid paste copy...",
                    "ERROR");
        }

    }

    @Override
    public MyDefaultMutableTreeNode[] getSelected() {
        return m_selected;
    }

    @Override
    public void setSelected(MyDefaultMutableTreeNode[] selected) {
        m_selected = selected;
    }

    @Override
    public MyDefaultMutableTreeNode[] getNotSelected() {
        return m_notSelected;
    }

    @Override
    public void setNotSelected(MyDefaultMutableTreeNode[] notSelected) {
        m_notSelected = notSelected;
    }

    private synchronized boolean showListOfDeletes(
            MyDefaultMutableTreeNode deleteNode) {
        LinkedList<MyDefaultMutableTreeNode> changeNodes =
                new LinkedList<MyDefaultMutableTreeNode>();
        LinkedList<DynamicMapDesignTreeNode> nodes =
                new LinkedList<DynamicMapDesignTreeNode>();
        try {
            Integer[] defaults = createCloneList(
                    (DynamicMapDesignTreeNode) deleteNode.getUserObject(),
                    nodes);
            startDynamicMapSelecter(nodes,
                    defaults, (DynamicMapDesignTreeNode) deleteNode.getUserObject(),
                    "Which ones to delete?",
                    false);
            MyDefaultMutableTreeNode originalNode = null;
            if (getSelected() != null && getSelected().length > 0) {
                for (int i = 0; i
                        < getSelected().length; i++) {
                    DynamicMapDesignTreeNode node = (DynamicMapDesignTreeNode) getSelected()[i].getUserObject();
                    if (!node.isClone()) {
                        originalNode = getSelected()[i];
                    }
                    changeNodes.add(getSelected()[i]);
                }


            } else {
                // User wants to change nothing! Just exit!
                return false;
            }
            boolean result = true;
            PersistentTransaction t = null;
            try {
                t = TestisDbPersistentManager.instance().
                        getSession().beginTransaction();

                for (int i = 0; i < changeNodes.size(); i++) {
                    DynamicMapDesignTreeNode node = (DynamicMapDesignTreeNode) getSelected()[i].getUserObject();
                    if (node.isClone()) {
                        result = safeDeleteWithTransaction(changeNodes.get(i), false);
                        if (!result) {
                            break;
                        }
                    }
                }
                if (originalNode != null) {
                    result = safeDeleteWithTransaction(originalNode, false);
                }
                if (result) {
                    t.commit();
                } else {
                    t.rollback();
                }
            } catch (Exception ex) {
                if (t != null) {
                    try {
                        t.rollback();
                    } catch (PersistentException ex1) {
                        ex1.printStackTrace();
                    }
                }
                ex.printStackTrace();
            }
        } finally {
            setSelected(null);
            setNotSelected(null);
        }
        return true;
    }

    private void startDynamicMapSelecter(
            LinkedList<DynamicMapDesignTreeNode> list,
            Integer[] defaultSelected, DynamicMapDesignTreeNode clickedNode,
            String title,
            boolean addchild) {
        TestDesignControllerList.newInstance().getSelectController().
                startDynamicMapSelecter(this,
                list,
                defaultSelected, clickedNode,
                title,
                addchild);
    }

    private synchronized boolean showListOfPasteCopy(DynamicMapDesignTreeNode copy,
            MyDefaultMutableTreeNode targetNode,
            boolean oneToToneCopy) {
        LinkedList<MyDefaultMutableTreeNode> changeNodes =
                new LinkedList<MyDefaultMutableTreeNode>();
        LinkedList<DynamicMapDesignTreeNode> nodes =
                new LinkedList<DynamicMapDesignTreeNode>();
        try {
            Integer[] defaults = createCloneList(
                    (DynamicMapDesignTreeNode) targetNode.getUserObject(),
                    nodes);
            startDynamicMapSelecter(nodes,
                    defaults, (DynamicMapDesignTreeNode) targetNode.getUserObject(),
                    "Which ones to add?",
                    true);
            if (getSelected() != null && getSelected().length > 0) {
                for (int i = 0; i < getSelected().length; i++) {
                    changeNodes.add(getSelected()[i]);
                }
            } else {
                // User wants to change nothing! Just exit!
                return false;
            }


            MyDefaultMutableTreeNode copyTarget;
            int addIndex;
            int indexOfOriginal = 0;
            for (int i = 0; i < changeNodes.size(); i++) {
                DynamicMapDesignTreeNode parentNode = (DynamicMapDesignTreeNode) changeNodes.get(i).getParent().getUserObject();
                if (!parentNode.isClone()) {
                    indexOfOriginal = i;
                    break;
                }
            }
            if (indexOfOriginal != 0) {
                MyDefaultMutableTreeNode selectedOriginal = changeNodes.get(indexOfOriginal);
                changeNodes.remove(indexOfOriginal);
                changeNodes.add(0, selectedOriginal);
            }
            PersistentTransaction t = null;
            try {
                t = TestisDbPersistentManager.instance().
                        getSession().beginTransaction();
                int originalAddIndex = 0;
                for (int i = 0; i < changeNodes.size(); i++) {
                    copyTarget = changeNodes.get(i);
                    addIndex = copyTarget.getParent().getIndex(copyTarget);
                    if (addIndex < 0) {
                        addIndex = originalAddIndex;
                    }
                    if (i == 0) {
                        originalAddIndex = addIndex;
                        if (!safeCopyWithTransaction(copy, (DynamicMapDesignTreeNode) copyTarget.getParent().getUserObject(), oneToToneCopy, addIndex, false)) {
                            System.out.println(" --- COPY OPERATION --- ");
                            System.out.println("Source: " + copy);
                            System.out.println("Target: " + changeNodes.get(i).getParent().
                                    getUserObject());
                            System.out.println("COPY FAILED!");
                            continue;
                        } else {
                            DynamicMapDesignTreeNode parentNode = (DynamicMapDesignTreeNode) copyTarget.getParent().getUserObject();
                            DynamicMapDesignTreeNode[] childNodes = parentNode.getChildren();
                            copy = childNodes[addIndex];
                        }
                    } else {
                        if (!safeCloneWithTransaction(copy, (DynamicMapDesignTreeNode) copyTarget.getParent().getUserObject(), addIndex, false)) {
                            System.out.println(" --- CLONE OPERATION --- ");
                            System.out.println("Source: " + copy);
                            System.out.println("Target: " + changeNodes.get(i).getParent().
                                    getUserObject());
                            System.out.println("CLONE FAILED!");
                            continue;
                        }
                    }
                }
                t.commit();
            } catch (Exception ex) {
                if (t != null) {
                    try {
                        t.rollback();
                    } catch (PersistentException ex1) {
                        ex1.printStackTrace();
                    }
                }
                ex.printStackTrace();
            }
        } finally {
            setSelected(null);
            setNotSelected(null);
        }
        return true;
    }

    private synchronized boolean showListOfPasteClone(
            DynamicMapDesignTreeNode clone,
            MyDefaultMutableTreeNode targetNode) {
        LinkedList<MyDefaultMutableTreeNode> changeNodes =
                new LinkedList<MyDefaultMutableTreeNode>();
        LinkedList<DynamicMapDesignTreeNode> nodes =
                new LinkedList<DynamicMapDesignTreeNode>();
        try {
            Integer[] defaults = createCloneList(
                    (DynamicMapDesignTreeNode) targetNode.getUserObject(),
                    nodes);
            startDynamicMapSelecter(nodes,
                    defaults, (DynamicMapDesignTreeNode) targetNode.getUserObject(),
                    "Which ones to add?",
                    true);
            if (getSelected() != null && getSelected().length > 0) {
                for (int i = 0; i < getSelected().length; i++) {
                    changeNodes.add(getSelected()[i]);
                }
            } else {
                // User wants to change nothing! Just exit!
                return false;
            }
            MyDefaultMutableTreeNode copyTarget;
            int addIndex;
            int indexOfOriginal = 0;
            for (int i = 0; i < changeNodes.size(); i++) {
                DynamicMapDesignTreeNode parentNode = (DynamicMapDesignTreeNode) changeNodes.get(i).getParent().getUserObject();
                if (!parentNode.isClone()) {
                    indexOfOriginal = i;
                    break;
                }
            }
            if (indexOfOriginal != 0) {
                MyDefaultMutableTreeNode selectedOriginal = changeNodes.get(indexOfOriginal);
                changeNodes.remove(indexOfOriginal);
                changeNodes.add(0, selectedOriginal);
            }
            PersistentTransaction t = null;
            try {
                t = TestisDbPersistentManager.instance().getSession().beginTransaction();
                int originalAddIndex = 0;
                for (int i = 0; i < changeNodes.size(); i++) {
                    copyTarget = changeNodes.get(i);
                    addIndex = copyTarget.getParent().getIndex(copyTarget);
                    if (addIndex < 0) {
                        addIndex = originalAddIndex;
                    }
                    if (i == 0) {
                        originalAddIndex = addIndex;
                    }
                    if (!safeCloneWithTransaction(clone,
                            (DynamicMapDesignTreeNode) copyTarget.getParent().getUserObject(), addIndex, false)) {
                        System.out.println(" --- CLONE OPERATION --- ");
                        System.out.println("Source: " + clone);
                        System.out.println("Target: " + changeNodes.get(i).getParent().
                                getUserObject());
                        System.out.println("CLONE FAILED!");
                        continue;
                    }
                }
                t.commit();
            } catch (Exception ex) {
                if (t != null) {
                    try {
                        t.rollback();
                    } catch (PersistentException ex1) {
                        ex1.printStackTrace();
                    }
                }
                ex.printStackTrace();
            }
        } finally {
            setSelected(null);
            setNotSelected(null);
        }
        return true;
    }

    private synchronized Integer[] createCloneList(DynamicMapDesignTreeNode node,
            LinkedList<DynamicMapDesignTreeNode> nodes) {
        Integer defaultSelected = null;
        DynamicMapDesignTreeNode originalNode;
        int nodeId = node.getId();
        if (node.isClone()) {
            originalNode = DynamicMapDesignTreeNode.getNode(node.getReference().
                    getClone());
        } else {
            originalNode = node;
        }
        T_dmap_designtree[] clones = originalNode.getClones();
        System.out.println("NO OF CLONES IS " + clones.length);
        for (int i = 0; i < clones.length; i++) {
            nodes.add(DynamicMapDesignTreeNode.getNode(clones[i]));
        }
        for (int i = 0; i < nodes.size(); i++) {
            if (nodes.get(i).getId() == nodeId) {
                defaultSelected = new Integer(i);
            }
        }
        if (originalNode.isGhost()) {
            if (!convertCloneOfGhostToOriginal(nodes.remove(
                    defaultSelected.intValue()),
                    originalNode)) {
                System.out.println(
                        "UNABLE TO CONVERT GHOST TO ORIGINAL! ABORTING!");
                return null;
            }
            originalNode = DynamicMapDesignTreeNode.getNode(originalNode.getReference());
            nodes.add(originalNode);
            defaultSelected = new Integer(nodes.size() - 1);
        } else {
            nodes.add(originalNode);
            if (defaultSelected == null) {
                defaultSelected = new Integer(nodes.size() - 1);
            }
        }
        return new Integer[]{defaultSelected};
    }

    private boolean convertCloneOfGhostToOriginal(DynamicMapDesignTreeNode clone,
            DynamicMapDesignTreeNode ghost) {
        return DynamicMap.newInstance().convertCloneOfGhostToOriginal(
                clone.getReference(),
                ghost.getReference());
    }

    private synchronized boolean showListOfAdds(DynamicMapAddable controller,
            DynamicMapDesignTreeNode node,
            HashMap<String, Object> params) {
        LinkedList<MyDefaultMutableTreeNode> changeNodes =
                new LinkedList<MyDefaultMutableTreeNode>();
        LinkedList<DynamicMapDesignTreeNode> nodes =
                new LinkedList<DynamicMapDesignTreeNode>();
        try {
            Integer[] defaults = createCloneList(node,
                    nodes);
            startDynamicMapSelecter(nodes,
                    defaults, node,
                    "Which ones to add?",
                    true);
            if (getSelected() != null && getSelected().length > 0) {
                for (int i = 0; i < getSelected().length; i++) {
                    changeNodes.add(getSelected()[i]);
                }
            } else {
                // User wants to change nothing! Just exit!
                return false;
            }

            MyDefaultMutableTreeNode copyTarget;
            DynamicMapDesignTreeNode copyParentNode;
            DynamicMapDesignTreeNode original = null;

            int j = 0;
            for (int k = 1; k < changeNodes.size(); k++) {
                copyTarget = changeNodes.get(k);
                copyParentNode = (DynamicMapDesignTreeNode) copyTarget.getParent().getUserObject();
                if (copyParentNode.getReference().getClone() == null) {
                    j = k;
                }
            }
            copyTarget = changeNodes.get(j);
            copyParentNode = (DynamicMapDesignTreeNode) copyTarget.getParent().
                    getUserObject();
            if (copyParentNode.isGhost()) {
                System.err.println(
                        "TRYING TO PASTE INTO A GHOST! THIS SHOULD NEVER HAPPEN!");
                return false;
            }
            int originalAddIndex = copyTarget.getParent().getIndex(copyTarget);
            original = controller.operationAddObject(params,
                    copyParentNode, originalAddIndex);
            if (original == null) {
                return false;
            }
            changeNodes.remove(j);
            PersistentTransaction t = null;
            try {
                t = TestisDbPersistentManager.instance().
                        getSession().beginTransaction();
                for (int i = 0; i < changeNodes.size(); i++) {
                    copyTarget = changeNodes.get(i);
                    copyParentNode = (DynamicMapDesignTreeNode) copyTarget.getParent().getUserObject();
                    int addIndex = copyTarget.getParent().getIndex(copyTarget);
                    if (addIndex == -1) {
                        addIndex = originalAddIndex;
                    }
                    DynamicMapDesignTreeNode temp = DynamicMap.newInstance().
                            operationPasteClone(original,
                            (DynamicMapDesignTreeNode) changeNodes.get(i).
                            getParent().getUserObject(), addIndex);
                    if (temp == null) {
                        System.out.println(" --- CLONE OPERATION --- ");
                        System.out.println("Source: " + original);
                        System.out.println("Target: " + changeNodes.get(i).getParent().
                                getUserObject());
                        System.out.println("CLONE FAILED!");
                        continue;
                    }
                }
                t.commit();
            } catch (Exception ex) {
                if (t != null) {
                    try {
                        t.rollback();
                    } catch (PersistentException ex1) {
                        ex1.printStackTrace();
                    }
                }
                ex.printStackTrace();
            }

        } finally {
            setSelected(null);
            setNotSelected(null);
        }
        return true;
    }

    private DynamicMapDesignTreeNode getUIDeviceMapContainerOfNode(DynamicMapDesignTreeNode node) {
        while (!node.getObject().getTypeName().equals("UIDeviceMapContainer")) {
            node = node.getParent();
        }
        return node;
    }

    private synchronized boolean showListOfClones(SaveAble controller,
            DynamicMapDesignTreeNode node,
            HashMap<String, Object> params) {
        LinkedList<MyDefaultMutableTreeNode> changeNodes =
                new LinkedList<MyDefaultMutableTreeNode>();
        LinkedList<MyDefaultMutableTreeNode> keepNodes =
                new LinkedList<MyDefaultMutableTreeNode>();
        LinkedList<DynamicMapDesignTreeNode> nodes =
                new LinkedList<DynamicMapDesignTreeNode>();
        try {
            Integer[] defaults = createCloneList(node,
                    nodes);
            startDynamicMapSelecter(nodes,
                    defaults, node,
                    "Which ones to change?",
                    false);
            boolean changeAll;
            boolean originalChanged = false;
            DynamicMapDesignTreeNode originalNode = null;
            DynamicMapDesignTreeNode temp;


            if (getSelected() != null && getSelected().length > 0) {
                for (int i = 0; i
                        < getSelected().length; i++) {
                    changeNodes.add(getSelected()[i]);
                    temp =
                            (DynamicMapDesignTreeNode) getSelected()[i].getUserObject();
                    if (!temp.isClone()) {
                        originalChanged = true;
                        originalNode =
                                temp;
                    }
                }
                if (changeNodes.size() == nodes.size()) {
                    changeAll = true;
                } else {
                    changeAll = false;
                    if (getNotSelected() != null) {
                        for (int i = 0; i
                                < getNotSelected().length; i++) {
                            keepNodes.add(getNotSelected()[i]);
                            temp =
                                    (DynamicMapDesignTreeNode) getNotSelected()[i].getUserObject();
                            if (!temp.isClone()) {
                                originalNode = temp;
                            }


                        }
                    }
                }
            } else {
                reloadAllTrees();
                // User wants to change nothing! Just exit!
                return false;
            }

            if (changeAll) {
                boolean isValidSave = controller.isValidSave(params, originalNode);
                if (isValidSave) {
                    return controller.operationSave(params,
                            originalNode,
                            false);
                } else {
                    return false;
                }
            } else {
                if (originalChanged) {
                    boolean isValidSave = controller.isValidSave(params, originalNode);
                    if (!isValidSave) {
                        return false;
                    }
                    boolean isChildsSaved = false;
                    PersistentTransaction t = null;
                    try {
                        t = TestisDbPersistentManager.instance().
                                getSession().beginTransaction();

                        DynamicMapDesignTreeNode originalNodeTestPlan = getUIDeviceMapContainerOfNode(originalNode);
                        DynamicMapDesignTreeNode keepNodesOriginalNode = null;
                        int indexOfKeepNode = 0;
                        for (int i = 0; i < keepNodes.size(); i++) {
                            DynamicMapDesignTreeNode tempNodeTestPlan = getUIDeviceMapContainerOfNode((DynamicMapDesignTreeNode) keepNodes.get(i).getUserObject());
                            if (tempNodeTestPlan.getReference().getId() == originalNodeTestPlan.getReference().getId()) {
                                indexOfKeepNode = i;
                                keepNodesOriginalNode = (DynamicMapDesignTreeNode) keepNodes.get(i).getUserObject();
                                break;
                            }
                        }
                        if (keepNodesOriginalNode != null) {
                            keepNodesOriginalNode.getReference().removeClone();
                            DynamicMapObject copyOf = originalNode.getObject().createRefinedDatabaseCopy();
                            keepNodesOriginalNode.setObject(copyOf);
                            keepNodesOriginalNode.getReference().setObject(copyOf.getReference());
                            keepNodesOriginalNode.getReference().save();
                            keepNodes.remove(indexOfKeepNode);
                            for (int i = 0; i < keepNodes.size(); i++) {
                                DynamicMapDesignTreeNode tmp = (DynamicMapDesignTreeNode) keepNodes.get(i).getUserObject();
                                tmp.getReference().setClone(
                                        keepNodesOriginalNode.getReference());
                                tmp.getReference().save();
                            }
                        } else {
                            //all other clones must be original. because they are on other test plans
                            for (int i = 0; i < keepNodes.size(); i++) {
                                DynamicMapDesignTreeNode keepNode = (DynamicMapDesignTreeNode) keepNodes.get(i).getUserObject();
                                keepNode.getReference().removeClone();
                                DynamicMapObject copyOf = originalNode.getObject().createRefinedDatabaseCopy();
                                keepNode.setObject(copyOf);
                                keepNode.getReference().setObject(copyOf.getReference());
                                keepNode.getReference().save();
                            }
                        }
                        t.commit();
                        isChildsSaved = true;
                    } catch (Exception ex) {
                        if (t != null) {
                            try {
                                t.rollback();
                            } catch (PersistentException ex1) {
                                ex1.printStackTrace();
                            }
                        }
                        ex.printStackTrace();
                    }
                    if (isChildsSaved) {
                        return controller.operationSave(params,
                                originalNode,
                                false);
                    }
                } else {
                    int indexOfChangeNodesOriginal = 0;
                    DynamicMapDesignTreeNode changeNodesOriginalNode = (DynamicMapDesignTreeNode) changeNodes.get(indexOfChangeNodesOriginal).getUserObject();
                    boolean isValidSave = controller.isValidSave(params, changeNodesOriginalNode);
                    if (!isValidSave) {
                        return false;
                    }
                    boolean isChildsSaved = false;
                    PersistentTransaction t = null;
                    try {
                        t = TestisDbPersistentManager.instance().
                                getSession().beginTransaction();
                        DynamicMapDesignTreeNode originalNodeTestPlan = getUIDeviceMapContainerOfNode(originalNode);
                        changeNodesOriginalNode = null;
                        int indexOfChangeNode = 0;
                        for (int i = 0; i < changeNodes.size(); i++) {
                            DynamicMapDesignTreeNode tempNodeTestPlan = getUIDeviceMapContainerOfNode((DynamicMapDesignTreeNode) changeNodes.get(i).getUserObject());

                            if (tempNodeTestPlan.getReference().getId() == originalNodeTestPlan.getReference().getId()) {
                                indexOfChangeNode = i;
                                changeNodesOriginalNode = (DynamicMapDesignTreeNode) changeNodes.get(i).getUserObject();
                                break;
                            }
                        }
                        if (changeNodesOriginalNode != null) {
                            changeNodesOriginalNode.getReference().removeClone();
                            DynamicMapObject copyOf = originalNode.getObject().createRefinedDatabaseCopy();
                            changeNodesOriginalNode.setObject(copyOf);
                            changeNodesOriginalNode.getReference().setObject(copyOf.getReference());
                            changeNodesOriginalNode.getReference().save();
                            changeNodes.remove(indexOfChangeNode);
                            for (int i = 0; i < changeNodes.size(); i++) {
                                DynamicMapDesignTreeNode tmp = (DynamicMapDesignTreeNode) changeNodes.get(i).getUserObject();
                                tmp.getReference().setClone(
                                        changeNodesOriginalNode.getReference());
                                tmp.getReference().save();
                            }
                        } else {//all other clones must be original. because they are on other test plans
                            for (int i = 0; i < changeNodes.size(); i++) {
                                DynamicMapDesignTreeNode changeNode = (DynamicMapDesignTreeNode) changeNodes.get(i).getUserObject();
                                changeNode.getReference().removeClone();
                                DynamicMapObject copyOf = originalNode.getObject().createRefinedDatabaseCopy();
                                changeNode.setObject(copyOf);
                                changeNode.getReference().setObject(copyOf.getReference());
                                changeNode.getReference().save();
                            }
                        }
                        t.commit();
                        isChildsSaved = true;
                    } catch (Exception ex) {
                        if (t != null) {
                            try {
                                t.rollback();
                            } catch (PersistentException ex1) {
                                ex1.printStackTrace();
                            }
                        }
                        ex.printStackTrace();
                    }
                    if (isChildsSaved) {
                        if (changeNodesOriginalNode != null) {
                            return controller.operationSave(params,
                                    changeNodesOriginalNode,
                                    false);
                        } else {//all other clones must be original. because they are on other test plans
                            for (int i = 0; i < changeNodes.size(); i++) {
                                DynamicMapDesignTreeNode changeNode = (DynamicMapDesignTreeNode) changeNodes.get(i).getUserObject();
                                if (!controller.operationSave(params,
                                        changeNode,
                                        false)) {
                                    return false;
                                }

                            }
                            return true;
                        }
                    }
                }
            }

        } finally {
            setSelected(null);
            setNotSelected(null);
            //   reloadIfStaleData();
        }
        return false;
    }

    public void operationReloadTree(Integer id) {
        System.out.println("RELOADING DEVICE MAP TREE ID: " + id + " NOW");
        MyDefaultMutableTreeNode child;
        MyDefaultMutableTreeNode root = DynamicMapControllerList.newInstance().
                getJDesignTreeRoot();
        for (int i = 0; i < root.getChildCount(); i++) {
            child = root.getChildAt(i);
            if (((DynamicMapDesignTreeNode) child.getUserObject()).getId() == id) {
                operationReloadTree(child,
                        id);
                return;
            }
        }
    }

    public void reloadAllTrees() {
        Integer[] ids = getLoadedTreeIds();
        for (int i = 0; i < ids.length; i++) {
            operationReloadTree(ids[i]);
        }
    }

    public void operationReloadTree(MyDefaultMutableTreeNode target) {
        operationReloadTree(target,
                ((DynamicMapDesignTreeNode) target.getUserObject()).getId());
    }

    public void operationReloadTree(MyDefaultMutableTreeNode target,
            Integer id) {
        this.operationCloseTree(target);
        this.operationLoadTreeFromDatabase(id);
        setModelProperty(TREE_RELOAD,
                true);
    }

    public void generateResponseOperation(MyDefaultMutableTreeNode nodeToAdd,
            boolean isNewTree,
            String message) {
        if (nodeToAdd != null) {
            if (isNewTree) {
                operationLoadTree(nodeToAdd);
            } else {
                operationSaveTree(nodeToAdd);
            }
            //this.operationSelectDesignPart(nodeToAdd);
            operationRefreshTree();
        } else {
            TestDesignControllerList.newInstance().getTreeController().
                    operationGenerateErrorMessage(message,
                    "ERROR");
        }
    }

    public void operationLoadTree(MyDefaultMutableTreeNode tree) {
        setModelProperty(TREE_LOAD,
                tree);
    }

    public void operationLoadTreeFromDatabase(String firmware,
            String dut) {
        DynamicMapDesignTreeNode root = null;
        try {
            int node = findLoadedDynamicMap(firmware,
                    dut);
            if (node != -1) {
                boolean result =
                        TestDesignControllerList.newInstance().getTreeController().
                        operationShowConfirmDialogBox(
                        "The DynamicMap part that you want to load is already open. Do you want to reload it?",
                        "Reload Tree?");
                if (result) {
                    this.operationCloseTree(deleteLoadedDynamicMap(node));
                } else {
                    return;
                }
            }
            root = DynamicMap.newInstance().getDynamicMapDesignTreeFomDB(false,
                    firmware,
                    dut);
        } catch (PersistentException ex) {
            ex.printStackTrace();
        }
        if (root != null) {
            operationLoadTree(new MyDefaultMutableTreeNode(root,
                    false));
            operationRefreshTree();
        }
    }

    public void operationLoadTreeFromDatabase(int treeId) {
        Timer t = new Timer();
        t.reset();
        DynamicMapDesignTreeNode root = null;
        try {
            root = DynamicMap.newInstance().getDynamicMapDesignTreeFomDB(treeId);
        } catch (PersistentException ex) {
        } catch (NoSuchDeviceException ex) {
            System.out.println("This map was already deleted");
        }
        if (root != null) {
            operationLoadTree(new MyDefaultMutableTreeNode(root,
                    false));
            operationRefreshTree();
        }
        t.print(treeId + " dynamic map tree loaded  in ms:");
    }

    public void operationCloseTree() {
        operationCloseTree(this.operationGetSelectedNode());
    }

    public void operationCloseTree(MyDefaultMutableTreeNode selectedNode) {
        LinkedList<MyDefaultMutableTreeNode> list =
                (LinkedList<MyDefaultMutableTreeNode>) getModelProperty(TREE_LOAD);
        for (int i = 0; i < list.size(); i++) {
            DynamicMapDesignTreeNode node = (DynamicMapDesignTreeNode) list.get(
                    i).
                    getUserObject();
            DynamicMapDesignTreeNode targetNode =
                    (DynamicMapDesignTreeNode) selectedNode.getUserObject();
            if (node.getId() == targetNode.getId()) {
                list.remove(i);
                break;
            }
        }
        MyDefaultMutableTreeNode parentNode = selectedNode.getParent();
        if (parentNode != null) {
            parentNode.remove(selectedNode);
            operationRefreshTree();
        }
    }

    public void operationSaveTree(MyDefaultMutableTreeNode tree) {
        setModelProperty(TREE_SAVE,
                tree);
    }

    synchronized public void operationPasteAttributes(
            DynamicMapDesignTreeNode copyObject,
            MyDefaultMutableTreeNode parentNode,
            boolean oneToOneCopy) throws PersistentException {
        DynamicMapDesignTreeNode pasteNode =
                (DynamicMapDesignTreeNode) parentNode.getUserObject();
        if (copyObject.getObject().getTypeName().equals("UIDeviceMapContainer")
                && pasteNode.getObject().getTypeName().equals("UIDeviceMapContainer")) {


            pasteNode.getObject().getParameterByName("LoginPageId").getReference().
                    setValue(copyObject.getObject().
                    getParameterByName("LoginPageId").getReference().
                    getValue());

            pasteNode.getObject().getParameterByName("FactorySettingsIp").
                    getReference().
                    setValue(copyObject.getObject().
                    getParameterByName("FactorySettingsIp").getReference().
                    getValue());

            pasteNode.getObject().getParameterByName("IpAddressTxtAbstractId").
                    getReference().
                    setValue(copyObject.getObject().
                    getParameterByName("IpAddressTxtAbstractId").
                    getReference().
                    getValue());

            pasteNode.getObject().getParameterByName("IpAddressBtnAbstractId").
                    getReference().
                    setValue(copyObject.getObject().
                    getParameterByName("IpAddressBtnAbstractId").
                    getReference().
                    getValue());
            pasteNode.getObject().getReference().save();
            DynamicMapParameter[] pars = pasteNode.getObject().getParameters();
            for (int i = 0; i < pars.length; i++) {
                System.out.println(i + ":"
                        + pars[i].getName()
                        + "-" + pars[i].getReference().
                        getValue());
            }
        }
    }

    synchronized public void operationPasteCopy(
            DynamicMapDesignTreeNode copyObject,
            MyDefaultMutableTreeNode parentNode,
            boolean oneToOneCopy) {
        if (copyObject.getObject().getTypeName().equals("UIDeviceMapContainer")) {
            DynamicMapDesignTreeNode[] children = copyObject.getChildren();
            boolean result = true;
            PersistentTransaction t = null;
            try {
                t = TestisDbPersistentManager.instance().
                        getSession().beginTransaction();
                for (int i = 0; i < children.length; i++) {
                    result = safeCopyWithTransaction(children[i],
                            (DynamicMapDesignTreeNode) parentNode.getUserObject(),
                            oneToOneCopy, i, false);
                    if (!result) {
                        break;
                    }
                }
                if (result) {
                    if (oneToOneCopy) {
                        Set keySet = newIdsOfOriginals.keySet();
                        Iterator<Integer> setIter = keySet.iterator();
                        while (setIter.hasNext()) {
                            Integer oldOriginalId = setIter.next();
                            Integer newOriginalId = newIdsOfOriginals.get(oldOriginalId);
                            DynamicMapDesignTreeNode originalNode = DynamicMapDesignTreeNode.getNodeById(newOriginalId);
                            List list = (List) cloneIdsOfOriginals.get(oldOriginalId);
                            if (list != null) {
                                for (int i = 0; i < list.size(); i++) {
                                    Integer newCloneId = (Integer) list.get(i);
                                    DynamicMapDesignTreeNode node = DynamicMapDesignTreeNode.getNodeById(newCloneId);
                                    node.getReference().setClone(originalNode.getReference());
                                    //refresh node
                                    node = DynamicMapDesignTreeNode.getNodeById(newCloneId);
                                    node.getReference().save();
                                    originalNode.getReference().save();
                                }
                            }
                        }
                    }
                    t.commit();
                } else {
                    t.rollback();
                }
            } catch (Exception ex) {
                if (t != null) {
                    try {
                        t.rollback();
                    } catch (PersistentException ex1) {
                        ex1.printStackTrace();
                    }
                }
                ex.printStackTrace();
            }
            if (!result) {
                TestDesignControllerList.newInstance().getTreeController().
                        operationGenerateErrorMessage("Invalid paste clone...",
                        "ERROR");
            } else {
                reloadAllTrees();
            }
        } else {
            operationHandlePasteCopy(copyObject,
                    parentNode,
                    oneToOneCopy);
        }
    }

    synchronized private boolean operationPasteCopyInternal(
            DynamicMapDesignTreeNode copyObject,
            DynamicMapDesignTreeNode parentTreeNode,
            boolean oneToOneCopy, OperationResultObject result, int childIndex) throws PersistentException {
        DynamicMapDesignTreeNode newCopyNode;
        if (copyObject.isClone() && oneToOneCopy) {
            newCopyNode = DynamicMap.newInstance().operationPasteClone(copyObject,
                    parentTreeNode, childIndex);
            if (newCopyNode != null) {
                cloneIdsOfOriginals.put(Integer.valueOf(copyObject.getReference().getClone().getId()), Integer.valueOf(newCopyNode.getId()));
            }
        } else {
            newCopyNode = DynamicMap.newInstance().operationPasteCopy(copyObject,
                    parentTreeNode, childIndex);
            if (newCopyNode != null && oneToOneCopy) {
                newIdsOfOriginals.put(copyObject.getId(), newCopyNode.getId());
            }
        }

        if (newCopyNode == null) {
            System.out.println(" --- COPY OPERATION --- ");
            System.out.print(" Source: " + newCopyNode);
            System.out.print(" Target: " + parentTreeNode);
            System.out.println(" COPY FAILED!");
            result.setResult(false);
            return false;
        } else//add flyweight node
        {
            DynamicMapDesignTreeNode.getNode(newCopyNode.getReference());
        }
        DynamicMapDesignTreeNode[] childNodes = copyObject.getChildren();
        int childCount = childNodes.length;
        for (int i = 0; i < childCount; i++) {
            if (!operationPasteCopyInternal(childNodes[i],
                    newCopyNode, oneToOneCopy,
                    result, i)) {
                System.out.println("COPY FAILED!");
                result.setResult(false);
                return false;
            }
        }
        return true;
    }

    synchronized public void operationPasteClone(
            DynamicMapDesignTreeNode cloneObject,
            MyDefaultMutableTreeNode parentNode) {
        if (cloneObject.getObject().getTypeName().equals("UIDeviceMapContainer")) {
            DynamicMapDesignTreeNode[] children = cloneObject.getChildren();
            boolean result = true;
            PersistentTransaction t = null;
            try {
                t = TestisDbPersistentManager.instance().
                        getSession().beginTransaction();
                for (int i = 0; i < children.length; i++) {
                    result = safeCloneWithTransaction(children[i],
                            (DynamicMapDesignTreeNode) parentNode.getUserObject(),
                            i, false);
                    if (!result) {
                        break;
                    }
                }
                if (result) {
                    t.commit();
                } else {
                    t.rollback();
                }
            } catch (Exception ex) {
                if (t != null) {
                    try {
                        t.rollback();
                    } catch (PersistentException ex1) {
                        ex1.printStackTrace();
                    }
                }
                ex.printStackTrace();
            }
            if (!result) {
                TestDesignControllerList.newInstance().getTreeController().
                        operationGenerateErrorMessage("Invalid paste clone...",
                        "ERROR");
            } else {
                reloadAllTrees();
            }
        } else {
            operationHandlePasteClone(cloneObject,
                    parentNode);
        }


    }

    private boolean safeCloneWithTransaction(DynamicMapDesignTreeNode clone, DynamicMapDesignTreeNode targetNode,
            int childIndex, boolean startTransaction) {
        OperationResultObject result = new OperationResultObject(
                true);
        PersistentTransaction t = null;
        try {
            if (startTransaction) {
                t = TestisDbPersistentManager.instance().getSession().beginTransaction();
            }
            operationPasteCloneInternal(clone,
                    targetNode,
                    result, childIndex);
            if (result.isResult() && startTransaction) {
                t.commit();
            }
        } catch (Exception ex) {
            result.setResult(false);
            if (t != null) {
                try {
                    t.rollback();
                } catch (PersistentException ex1) {
                    ex1.printStackTrace();
                }
            }
            ex.printStackTrace();
        }
        return result.isResult();
    }

    synchronized public boolean operationPasteCloneInternal(DynamicMapDesignTreeNode cloneObject,
            DynamicMapDesignTreeNode parentTreeNode,
            OperationResultObject result, int childIndex) throws PersistentException {

        DynamicMapDesignTreeNode newCloneNode = DynamicMap.newInstance().operationPasteClone(cloneObject,
                parentTreeNode, childIndex);
        if (newCloneNode == null) {
            System.out.println(" --- CLONE OPERATION --- ");
            System.out.print(" Source: " + newCloneNode);
            System.out.print(" Target: " + parentTreeNode);
            System.out.println(" CLONE FAILED!");
            result.setResult(false);
            return false;
        }
        DynamicMapDesignTreeNode[] childNodes = cloneObject.getChildren();
        int childCount = childNodes.length;
        for (int i = 0; i < childCount; i++) {
            if (!operationPasteCloneInternal(childNodes[i],
                    newCloneNode,
                    result, i)) {
                System.out.println("CLONE FAILED!");
                result.setResult(false);
                return false;
            }
        }
        return true;

    }

    public void operationSelectDesignPart(MyDefaultMutableTreeNode node,
            int selectMode) {
        if (node != null && node.getUserObject() != null
                && node.getUserObject() instanceof DynamicMapDesignTreeNode) {
            setModelProperty(SELECT_DESIGN_PART,
                    node);
            setModelProperty(SHOW_PROPERTIES,
                    node.getUserObject().toString());
        } else {
            setModelProperty(SHOW_PROPERTIES,
                    "");
        }
        if (selectMode == 1 && node != null) {
            node.setColor(MyDefaultMutableTreeNode.COMPARE);
            if (!isSourceSelected()) {
                operationSetSource(node);
                setSourceSelected(true);
            } else {
                operationSetDestination(node);
                MyDefaultMutableTreeNode source = operationGetSource();
                MyDefaultMutableTreeNode destination = operationGetDestination();
                compare(source,
                        destination);
                operationSelectCompareMode(false);
                operationRefreshTree();
            }
        }
    }

    public void operationSelectCompareMode(Boolean mode) {
        if (!mode) {
            MyDefaultMutableTreeNode source = operationGetSource();
            MyDefaultMutableTreeNode destination = operationGetDestination();
            if (source != null) {
                source.setColor(MyDefaultMutableTreeNode.DEFAULT);
            }
            if (destination != null) {
                destination.setColor(MyDefaultMutableTreeNode.DEFAULT);
            }
            setSourceSelected(false);
        }
        setModelProperty(COMPARE_MODE_ON,
                mode);
    }

    private boolean isSourceSelected() {
        return m_sourceSelected;
    }

    private void setSourceSelected(boolean sourceSelected) {
        m_sourceSelected = sourceSelected;
    }

    private void operationSetSource(MyDefaultMutableTreeNode src) {
        setModelProperty(SOURCE,
                src);
    }

    private MyDefaultMutableTreeNode operationGetSource() {
        return (MyDefaultMutableTreeNode) getModelProperty(SOURCE);
    }

    private MyDefaultMutableTreeNode operationGetDestination() {
        return (MyDefaultMutableTreeNode) getModelProperty(DESTINATION);
    }

    private void operationSetDestination(MyDefaultMutableTreeNode dst) {
        setModelProperty(DESTINATION,
                dst);
    }

    public void operationValidateTree() {
        DynamicMapDesignTreeNode root = (DynamicMapDesignTreeNode) operationGetSelectedNode().getUserObject();
        root.validate(root);
        operationExpandToNextNode();
    }

    public void operationExpandToNextInvalidNode() {
        try {
            MyDefaultMutableTreeNode node = getNextInvalidNode(operationGetSelectedNode());
            if (node != null) {
                setModelProperty(SELECT_DESIGN_PART,
                        node);
            }
        } catch (StackOverflowError ex) {
            TestDesignControllerList.newInstance().getTreeController().
                    operationGenerateErrorMessage("Too many nodes to search...",
                    "ERROR");
        }
    }

    private MyDefaultMutableTreeNode getNextInvalidNode(MyDefaultMutableTreeNode mnode) {
        if (mnode == null) {
            return null;
        }
        DynamicMapDesignTreeNode node = (DynamicMapDesignTreeNode) mnode.getUserObject();
        if (!node.isValid() && mnode != operationGetSelectedNode()) {
            return mnode;
        }
        int childCount = mnode.getChildCount();
        if (childCount > 0) {
            for (int i = 0; i < childCount; i++) {
                return getNextInvalidNode(mnode.getChildAt(i));
            }
        } else {
            while (mnode.getNextSibling() == null) {
                mnode = mnode.getParent();
                if (mnode == null) {
                    return null;
                }
            }
            return getNextInvalidNode(mnode.getNextSibling());
        }
        return null;
    }

    public void operationChangeLastSearch(String searchValue) {
        m_lastSearchValue = searchValue;
    }

    public void operationFindNextNodeByText() {
        try {
            MyDefaultMutableTreeNode node = getNextNodeContainsValue(operationGetSelectedNode());
            if (node != null) {
                setModelProperty(SELECT_DESIGN_PART,
                        node);
            }
        } catch (StackOverflowError ex) {
            TestDesignControllerList.newInstance().getTreeController().
                    operationGenerateErrorMessage("Too many nodes to search...",
                    "ERROR");
        }
    }

    private MyDefaultMutableTreeNode getNextNodeContainsValue(MyDefaultMutableTreeNode mnode) {
        if (mnode == null) {
            return null;
        }
        DynamicMapDesignTreeNode node = (DynamicMapDesignTreeNode) mnode.getUserObject();
        if (node.getName().contains(m_lastSearchValue) && mnode != operationGetSelectedNode()) {
            return mnode;
        } else if (StringVerification.verifyText(m_lastSearchValue, node.getName()) && mnode != operationGetSelectedNode()) {
            return mnode;
        } else {
            DynamicMapObject mapObject = node.getObject();
            LinkedList<DynamicMapParameter> paramList = mapObject.getParametersLinkedList();
            if (paramList.size() > 0) {
                Iterator<DynamicMapParameter> it = paramList.iterator();
                while (it.hasNext()) {
                    DynamicMapParameter param = it.next();
                    if (param.getName().toUpperCase().contains(m_lastSearchValue.toUpperCase()) && mnode != operationGetSelectedNode()) {
                        return mnode;
                    } else if (StringVerification.verifyText(m_lastSearchValue, param.getName()) && mnode != operationGetSelectedNode()) {
                        return mnode;
                    } else if (param.getValue().toUpperCase().contains(m_lastSearchValue.toUpperCase()) && mnode != operationGetSelectedNode()) {
                        return mnode;
                    } else if (StringVerification.verifyText(m_lastSearchValue, param.getValue()) && mnode != operationGetSelectedNode()) {
                        return mnode;
                    }
                }
            }
        }
        int childCount = mnode.getChildCount();
        if (childCount > 0) {
            for (int i = 0; i < childCount; i++) {
                return getNextNodeContainsValue(mnode.getChildAt(i));
            }
        } else {
            while (mnode.getNextSibling() == null) {
                mnode = mnode.getParent();
                if (mnode == null) {
                    return null;
                }
            }
            return getNextNodeContainsValue(mnode.getNextSibling());
        }
        return null;
    }

    public void operationDeleteTreeNode() {
        operationHandleDelete(operationGetSelectedNode());
        operationRefreshTree();
    }

    synchronized private void validateIntegrity(DynamicMapDesignTreeNode treeNode) {
        if (treeNode == null) {
            return;
        }
        if (treeNode.getReference() != null
                && treeNode.getReference().t_dmap_designtree != null
                && treeNode.getReference().t_dmap_designtree.size() > 0) {
            if (!(treeNode.getChildren() != null
                    && treeNode.getChildren().length
                    == treeNode.getReference().t_dmap_designtree.size())) {
                DynamicMap.newInstance().fixChildren(treeNode);
                DynamicMapDesignTreeNode[] childNode = treeNode.getChildren();
                for (int i = 0; i < treeNode.getChildren().length; i++) {
                    validateIntegrity(childNode[i]);
                }
            }
        }
    }

    public DynamicMapDesignTreeNode operationGetSelectedDesignPart() {
        if (operationGetSelectedNode() != null && operationGetSelectedNode().
                getUserObject() instanceof DynamicMapDesignTreeNode) {
            return (DynamicMapDesignTreeNode) operationGetSelectedNode().
                    getUserObject();
        } else {
            return null;
        }
    }

    public MyDefaultMutableTreeNode operationGetSelectedNode() {
        return (MyDefaultMutableTreeNode) getModelProperty(SELECT_DESIGN_PART);
    }

    synchronized public void moveObject(DynamicMapDesignTreeNode currentNode,
            DynamicMapDesignTreeNode newNextNode) {
        DynamicMapDesignTreeNode parent = currentNode.getParent();
//        for (int m = 0; m < parent.getChildrenLinkedList().size(); m++) {
//            System.out.println(((DynamicMapDesignTreeNode) parent.getChildrenLinkedList().get(m)).getId());
//        }
        for (int i = 0; i < parent.getChildrenLinkedList().size(); i++) {
            if (parent.getChild(i).getId() == currentNode.getId()) {
                DynamicMapDesignTreeNode obj = (DynamicMapDesignTreeNode) parent.getChildrenLinkedList().
                        remove(i);
                if (newNextNode != null) {
                    for (int j = 0; j < parent.getChildrenLinkedList().size();
                            j++) {
                        if (parent.getChild(j).getId() == newNextNode.getId()) {
                            parent.getChildrenLinkedList().add(j,
                                    obj);
                            return;
                        }
                    }
                } else {
                    parent.getChildrenLinkedList().add(obj);
                }
            }
        }
    }

    @Override
    public boolean moveObject(MyDefaultMutableTreeNode currentPrevNode,
            MyDefaultMutableTreeNode currentNextNode,
            MyDefaultMutableTreeNode newPrevNode,
            MyDefaultMutableTreeNode newNextNode,
            MyDefaultMutableTreeNode currentNode) {
        DynamicMapDesignTreeNode currentPrevTreeNode = null;
        DynamicMapDesignTreeNode currentNextTreeNode = null;
        DynamicMapDesignTreeNode newPrevTreeNode = null;
        DynamicMapDesignTreeNode newNextTreeNode = null;
        DynamicMapDesignTreeNode currentTreeNode = null;
        System.out.println("currentPrevNode = " + currentPrevNode);
        System.out.println("currentNextNode = " + currentNextNode);
        System.out.println("newPrevNode = " + newPrevNode);
        System.out.println("newNextNode = " + newNextNode);
        System.out.println("currentNode = " + currentNode);
        if (currentNode == null) {
            return false;
        } else {
            currentTreeNode = (DynamicMapDesignTreeNode) currentNode.getUserObject();
        }
        if (currentPrevNode != null) {
            currentPrevTreeNode = (DynamicMapDesignTreeNode) currentPrevNode.getUserObject();
        }
        if (currentNextNode != null) {
            currentNextTreeNode = (DynamicMapDesignTreeNode) currentNextNode.getUserObject();
        }
        if (newNextNode != null) {
            newNextTreeNode = (DynamicMapDesignTreeNode) newNextNode.getUserObject();
        }
        if (newPrevNode != null) {
            newPrevTreeNode = (DynamicMapDesignTreeNode) newPrevNode.getUserObject();
        }
        if (currentTreeNode == null || (currentTreeNode != null && currentTreeNode.getTypeName().
                equals("UIDeviceMapContainer"))) {
            return false;
        }
        if (true) {
            DynamicMap.newInstance().handleMoveObjectRanks(currentPrevTreeNode,
                    currentNextTreeNode,
                    newPrevTreeNode,
                    newNextTreeNode,
                    currentTreeNode);
            moveObject(currentTreeNode,
                    newNextTreeNode);
            return true;
        } else {
            return false;
        }
    }

    public String[] getLoadedTrees() {
        LinkedList<MyDefaultMutableTreeNode> list =
                (LinkedList<MyDefaultMutableTreeNode>) getModelProperty(TREE_LOAD);
        String[] result = new String[list.size()];
        for (int i = 0; i < list.size(); i++) {
            DynamicMapDesignTreeNode temp = (DynamicMapDesignTreeNode) list.get(i).getUserObject();
            if (temp != null) {
                if (temp.isClone()) {
                    result[i] = temp.getReference().getClone().getId() + " -- " + temp.getName();
                } else {
                    result[i] = temp.getId() + " -- " + temp.getName();
                }
            }
        }
        return result;
    }

    public Integer[] getLoadedTreeIds() {
        LinkedList<MyDefaultMutableTreeNode> list =
                (LinkedList<MyDefaultMutableTreeNode>) getModelProperty(TREE_LOAD);
        Integer[] result = new Integer[list.size()];
        DynamicMapDesignTreeNode temp;
        for (int i = 0; i < list.size(); i++) {
            temp = (DynamicMapDesignTreeNode) list.get(i).getUserObject();
            if (temp != null) {
                if (temp.isClone()) {
                    result[i] = temp.getReference().getClone().getId();
                } else {
                    result[i] = temp.getId();
                }
            }
        }
        return result;
    }

    private int findLoadedDynamicMap(String firmware,
            String dut) {
        LinkedList<MyDefaultMutableTreeNode> list =
                (LinkedList<MyDefaultMutableTreeNode>) getModelProperty(TREE_LOAD);
        Integer mapId = DynamicMap.newInstance().
                getFirmwareByNameAndDutName(firmware,
                dut).getDeviceMapId();
        if (mapId == null) {
            TestDesignControllerList.newInstance().getTreeController().
                    operationGenerateErrorMessage(
                    "Dynamic map not set for dut:" + dut + " firmware:" + firmware,
                    "Warning!");
        }
        T_dmap_designtreeCriteria cri;
        try {
            cri = new T_dmap_designtreeCriteria();
            cri.id.eq(mapId);
            T_dmap_designtree t_dmap_designtree = cri.uniqueT_dmap_designtree();
            for (int i = 0; i < list.size(); i++) {
                DynamicMapDesignTreeNode node = (DynamicMapDesignTreeNode) list.get(
                        i).
                        getUserObject();
                if (node != null && node.getId() == t_dmap_designtree.getId()) {
                    return i;
                }
            }
        } catch (PersistentException ex) {
            ex.printStackTrace();
        }

        return -1;
    }

    private MyDefaultMutableTreeNode deleteLoadedDynamicMap(int map) {
        LinkedList<MyDefaultMutableTreeNode> list =
                (LinkedList<MyDefaultMutableTreeNode>) getModelProperty(TREE_LOAD);
        return list.remove(map);
    }

    synchronized private void compare(MyDefaultMutableTreeNode src,
            MyDefaultMutableTreeNode dst) {

        TestDesignControllerList.newInstance().getCompareGUIController().
                start(
                src,
                dst,
                this);

    }

    @Override
    public boolean executeOperation(Operation operation) {
        MyDefaultMutableTreeNode selectedNode;
        MyDefaultMutableTreeNode selectedParentNode;
        MyDefaultMutableTreeNode destinationGuiNode;
        if (operation.getSource().getUserObject() instanceof DynamicMapDesignTreeNode
                && operation.getDestination().getUserObject() instanceof DynamicMapDesignTreeNode) {
            DynamicMapDesignTreeNode source = (DynamicMapDesignTreeNode) operation.getSource().
                    getUserObject();
            destinationGuiNode = operation.getDestination();
            if (operation.getOperation().equals(Operation.COPY)) {
                if (operation.isReplace()) {
                    operationHandlePasteCopy(source, destinationGuiNode.getParent(), false);

                } else {
                    operationHandlePasteCopy(source, destinationGuiNode, false);
                    return true;
                }
            } else if (operation.getOperation().equals(Operation.CLONE)) {
                if (operation.isReplace()) {
                    operationHandlePasteClone(source,
                            destinationGuiNode.getParent());
                } else {
                    operationHandlePasteClone(source,
                            destinationGuiNode);
                    return true;
                }
            } else {
                return false;
            }
            selectedNode = operationGetSelectedNode();
            selectedParentNode = selectedNode.getParent();
            int index = selectedParentNode.getIndex(destinationGuiNode);
            if (index + 1 == selectedParentNode.getIndex(selectedNode)) {
                operationHandleDelete(destinationGuiNode);
                return true;
            } else {
                if (moveObject(null,
                        null,
                        destinationGuiNode,
                        destinationGuiNode.getNextSibling(),
                        selectedNode)) {
                    operationHandleDelete(destinationGuiNode);
                    selectedNode.removeFromParent();
                    selectedParentNode.insert(selectedNode,
                            index);
                    return true;
                }
            }
        }
        return false;
    }

    public DynamicMapDesignTreeNode operationGetRootOfSelectedNode() {
        DynamicMapDesignTreeNode selectedNode = operationGetSelectedDesignPart();
        if (selectedNode != null) {
            return findRoot(selectedNode);
        }
        return null;
    }

    private DynamicMapDesignTreeNode findRoot(DynamicMapDesignTreeNode node) {
        if (node.getParent() == null) {
            return node;
        }
        return findRoot(node.getParent());
    }


    public void operationClearSelection() {
        setModelProperty(CLEAR_SELECTION_PROPERTY, Boolean.TRUE);
    }

    public void operationExpandToNextNode() {
        if (m_lastSearchValue.isEmpty()) {
            operationExpandToNextInvalidNode();
        } else {
            operationFindNextNodeByText();
        }
    }
}
